﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OOAD_Project_Editor.Foundation.Script;
using OOAD_Project_Editor.Foundation;
using OOAD_Project_Engine.Foundation;
using System.Reflection;
using OOAD_Project_Engine.Foundation.Interfaces;

namespace OOAD_Project_Editor.Domain
{
    class ScriptFactory
    {
        static ScriptFactory factory;

        public static ScriptFactory GetInstance()
        {
            if (factory != null)
                return factory;
            else
            {
                factory = new ScriptFactory();
                return factory;
            }
        }

        public SceneScript ToScript(IEditableSceneComponent scene)
        {

            SceneScript script = new SceneScript();

            script.Name = "Scene";
            foreach (IEntity entity in scene.AllEntitys.Values)
            {
                if (entity.GetType().GetCustomAttributes(typeof(SerializableAttribute), false).Length > 0)
                {
                    EntityScript es = getScript(entity);
                    script.EntityScript.Add(es);
                }
            }
            return script;

        }

        EntityScript getScript(IEntity entity)
        {
            EntityScript es = new EntityScript();
            es.Name = entity.Name;
            es.HasParent = entity.Parent != null;

            foreach (IEntityComponent c in entity)
            {
                EntityComponentScript ecs = getScript(c);
                es.EntityComponentScripts.Add(ecs);
            }

            return es;
        }

        EntityComponentScript getScript(IEntityComponent component)
        {
            EntityComponentScript ecs = new EntityComponentScript();

            Type t = component.GetType();
            ecs.ComponentType = t.AssemblyQualifiedName;

            ecs.CustomProperties = getSerializeProperty(component);
            ecs.ConstructorParameters = getConstructorParameters(component);

            return ecs;
        }

        List<object> getConstructorParameters(IEntityComponent component)
        {
            List<object> paras = new List<object>();
            SortedList<int, object> paramlist = new SortedList<int, object>();
            Type t = component.GetType();
            PropertyInfo[] ps = t.GetProperties();

            foreach (PropertyInfo p in ps)
            {
                object[] os = p.GetCustomAttributes(typeof(ConstructorParameterAttribute), true);
                foreach (object att in os)
                {
                    ConstructorParameterAttribute para = att as ConstructorParameterAttribute;
                    object value = p.GetValue(component, null);
                    int index = para.Index;
                    paramlist.Add(index, value);
                }
            }
            foreach (object o in paramlist.Values)
                paras.Add(o);
            return paras;
        }

        List<CustomProperty> getSerializeProperty(IEntityComponent component)
        {
            List<CustomProperty> properties = new List<CustomProperty>();

            Type t = component.GetType();
            PropertyInfo[] ps = t.GetProperties();

            foreach (PropertyInfo p in ps)
            {
                bool serializable = false;
                object[] os = p.GetCustomAttributes(typeof(ComponentPropertyAttribute), true);
                foreach (object att in os)
                {
                    ComponentPropertyAttribute cat = att as ComponentPropertyAttribute;
                    serializable = cat.Serializable;
                }
                if (serializable)
                {
                    CustomProperty cp = new CustomProperty(p.Name, p.GetValue(component, null));
                    properties.Add(cp);
                }
            }
            return properties;
        }

    }
}
